/*
 *  Netzpult - Your desk on the web
 *  Copyright (C) 2011  Ulrich Hilger, http://uhilger.de
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see http://www.gnu.org/licenses/
 */

package de.uhilger.netzpult.client;

import java.util.Iterator;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.SplitLayoutPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.TreeItem;
import com.google.gwt.user.client.ui.VerticalPanel;

import de.uhilger.netzpult.shared.App;
import de.uhilger.netzpult.shared.Document;
import de.uhilger.netzpult.shared.Folder;

/**
 * Bedienoberfläche für öffentliche Internetseiten der Webanwendung Netzpult
 * 
 * @author Copyright (c) Ulrich Hilger, http://uhilger.de
 * @author Published under the terms and conditions of
 * the <a href="http://www.gnu.org/licenses/" target="_blank">GNU General Public License</a>
 */
public class Seite extends AbstrakteGestalt {

	private final PublicServiceAsync publicService = GWT
			.create(PublicService.class);
	
	//private static final String SEITEN_LINK = "/seiten/";
	private static final String DOK_LINK = "/dok/";

	private BoundTree tree;
	private Grid publicDocSpace;
	private String docId;
	private AsyncListener listener;
	private HTML docInfo;
	private HTML linksHeader;
	private TextBox suche;
	
	public Seite(AsyncListener listener) {
		super();
		this.listener = listener;

		String owner = null;
		String[] path = Window.Location.getPath().split("/");
		
		/*
		String msg = "";
		for(int i=0; i < path.length; i++) {
			msg = msg + "path[" + i + "]=" + path[i] + "\r\n";
		}
		msg = msg + "path length = " + path.length;
		GWT.log(msg);
		//Window.alert(msg);
		*/
		
		switch(path.length) {
		case 1:
			docId = path[0];
			owner = null;
			break;
		case 2:
			docId = path[1];
			owner = null;
			break;
		case 3:
			docId = path[2];
			//owner = path[1];
			break;
		case 4:
			owner = path[2];
			docId = path[3];
			break;
		}
		if(docId == null || docId.length() < 1) {
			publicService.getDefaultDocument(new GetDefaultDocumentHandler());
		} else {
			if (owner == null) {
				try {
				publicService.getDocumentOwner(Integer.parseInt(docId), new GetOwnerHandler());
				} catch(NumberFormatException e) {
					publicService.getDefaultDocument(new GetDefaultDocumentHandler());
				}
			} else {
				buildUi(owner, true);
			}
		}
	}

	private void buildUi(String owner, boolean delay) {
		ScrollPanel treePanel = new ScrollPanel();
		treePanel.setStyleName("publicUINavPanel");
		tree = new BoundTree(owner, true);
		tree.setService(publicService);
		tree.addSelectionHandler(new TreeSelectionHandler(owner));
		treePanel.setWidget(tree);
		tree.setSize("100%", "100%");

		publicDocSpace = new Grid(1, 1);

		ScrollPanel docPanel = new ScrollPanel();
		docPanel.setWidget(publicDocSpace);
		docPanel.setStyleName("publicUIDocPanel");
		
		docInfo = new HTML();
		docInfo.setStyleName("seiteKopfLinks");
		
		linksHeader = new HTML();
		linksHeader.setStyleName("seiteKopfRechts");

		Grid headerPanel = new Grid(1, 2);
		headerPanel.setWidget(0, 0, docInfo);
		headerPanel.setWidget(0, 1, linksHeader);
		headerPanel.setWidth("100%");
		headerPanel.getColumnFormatter().setStyleName(0, "seiteKopfLinks");
		headerPanel.getColumnFormatter().setStyleName(1, "seiteKopfRechts");
		headerPanel.getCellFormatter().setHorizontalAlignment(0, 1, HasHorizontalAlignment.ALIGN_RIGHT);
		
		DockLayoutPanel docContainer = new DockLayoutPanel(Unit.PX);
		docContainer.addNorth(headerPanel, 16.0);
		docContainer.add(docPanel);
		
		docContainer.setStyleName("publicDocSpace");
		
		suche = new TextBox();
		suche.setText("Suchbegriff");
		suche.addKeyDownHandler(new SearchHandler(owner));		
		
		/*
		sucheBtn = new Button("finden");
		HorizontalPanel suchPanel = new HorizontalPanel();
		suchPanel.add(suche);
		suchPanel.add(sucheBtn);
		*/
		
		Anchor appLink = new Anchor(App.NAME, "http://netzpult.de");
		appLink.setStyleName("publicUICopyright");
		
		VerticalPanel vp = new VerticalPanel();
		vp.add(suche);
		vp.add(appLink);
		vp.setCellHorizontalAlignment(suche, HasHorizontalAlignment.ALIGN_CENTER);
		vp.setCellHorizontalAlignment(appLink, HasHorizontalAlignment.ALIGN_CENTER);
		
		DockLayoutPanel nav = new DockLayoutPanel(Unit.PX);
		nav.addSouth(vp, 50.0);
		nav.add(treePanel);
		
		SplitLayoutPanel ablage = new SplitLayoutPanel();
		ablage.addWest(nav, 200.0);
		ablage.add(docContainer);
		
		Folder parentFolder = Folder.getPublicFolder();
		publicService.getDocuments(owner, parentFolder, new RootDocumentsHandler(
				owner));


		initWidget(ablage);
		//uiReady = true;
		if(delay) {
			Timer t = new Timer() {

				@Override
				public void run() {
					listener.isDone();
				}
			};
			t.schedule(5);
		} else {
			listener.isDone();
		}
	}
	
	/*
	 * Ereignisbearbeitung
	 */
	
	private class SearchHandler implements KeyDownHandler {
		
		private String searchOwner;
		
		public SearchHandler(String owner) {
			this.searchOwner = owner;
		}

		@Override
		public void onKeyDown(KeyDownEvent event) {
			int keyCode = event.getNativeKeyCode();
			if(keyCode == KeyCodes.KEY_ENTER) {
				publicService.findDocuments(searchOwner, suche.getText(), new SearchResultsHandler());
			}
		}
		
	}

	private class TreeSelectionHandler implements SelectionHandler<TreeItem> {
		private String owner;

		public TreeSelectionHandler(String owner) {
			this.owner = owner;
		}

		public void onSelection(SelectionEvent<TreeItem> event) {
			Object selectedItem = event.getSelectedItem();
			if (selectedItem instanceof TreeItem) {
				TreeItem selectedTreeItem = (TreeItem) selectedItem;
				if (selectedTreeItem.getChildCount() > 0) {
					// tue nichts
				} else {
					Document doc = (Document) selectedTreeItem.getUserObject();
					String idStr = Integer.toString(doc.getId());
					publicService.getDocument(owner, idStr, new GetDocumentHandler());
				}
			}
		}
	}

	/*
	 * innere Klassen f�r die asynchrone Weiterverarbeitung von Server-Aufrufen
	 */
	
	private class SearchResultsHandler implements AsyncCallback<List<Document>> {

		@Override
		public void onFailure(Throwable caught) {
			Window.alert("Webfiles.showPublicDocument getDocument error "
					+ caught.getMessage());
		}

		@Override
		public void onSuccess(List<Document> result) {
			StringBuffer buf = new StringBuffer();
			buf.append("<h3>Suchergebnis</h3>");
			Iterator<Document> i = result.iterator();
			while(i.hasNext()) {
				Document document = i.next();
				buf.append("<p>");
				buf.append("<a href=\"");
				buf.append(document.getId());
				buf.append("\">");
				buf.append(document.getTitle());
				buf.append("</a>");
				buf.append("</p>");
			}
			publicDocSpace.setHTML(0, 0, buf.toString());
		}
		
	}

	private class GetDocumentHandler implements AsyncCallback<Document> {
		
		//private String docOwner;
		
		/*public GetDocumentHandler(String docOwner) {
			this.docOwner = docOwner;
		}*/
		
		public void onFailure(Throwable caught) {
			Window.alert("Webfiles.showPublicDocument getDocument error "
					+ caught.getMessage());
		}

		public void onSuccess(Document result) {
			/*
			 * hier nehmen wir an, dass der Browser PDFs darstellen kann
			 */
			String mimeType = result.getMimeType();
			if(mimeType.equalsIgnoreCase("text/html") || mimeType.equalsIgnoreCase("application/pdf")) {
				publicDocSpace.setHTML(0, 0, result.getContent());
			} else if (mimeType.contains("image")){
				publicDocSpace.setHTML(0, 0, "<img src=\"dok/" + result.getId() + "\">");
			} else {
				publicDocSpace.setHTML(0, 0, "<a href=\"dok/" + result.getId() + "\">" + result.getTitle() + "</a>");
			}
			
			StringBuffer buf = new StringBuffer();
			buf.append("<a href=\"");
			buf.append(DOK_LINK);
			/*if(docOwner != null) {
				buf.append(docOwner + "/");
			}*/
			buf.append(result.getId());
			buf.append("\">Navigation aus</a> | <a href=\"https://");
			buf.append(Window.Location.getHost());
			buf.append("/ablage\">Anmeldung</a> | ");
			buf.append("<a href=\"");
			buf.append("/");
			//buf.append(SEITEN_LINK);
			buf.append(result.getId());
			buf.append("\">Permalink</a>");
			linksHeader.setHTML(buf.toString());
			
			buf = new StringBuffer();
			buf.append("Dokument Nr. ");
			buf.append(result.getId());
			buf.append(", Version ");
			int version = result.getVersion();
			if(version == Document.DRAFT_VERSION_ID) {
				buf.append("Entwurf");
			} else {
				buf.append(version);
			}
			buf.append("&nbsp;&nbsp;&nbsp;&nbsp;");
			buf.append(result.getCreationTimeStr());			
			docInfo.setHTML(buf.toString());
		}
	}
	
	private class GetOwnerHandler implements AsyncCallback<String> {
		public void onFailure(Throwable caught) {
			Window.alert("Seite.buildPublicUi getDefaultOwner error: "
					+ caught.getMessage());
		}

		public void onSuccess(String result) {
			
			buildUi(result, false);
		}
	}

	private class GetDefaultDocumentHandler implements AsyncCallback<String> {
		public void onFailure(Throwable caught) {
			Window.alert("Seite.buildPublicUi getDefaultDocument error: "
					+ caught.getMessage());
		}

		public void onSuccess(String result) {
			docId = result;
			publicService.getDocumentOwner(Integer.parseInt(result), new GetOwnerHandler());
		}
	}

	private class RootDocumentsHandler implements AsyncCallback<List<Document>> {
		private String owner;

		public RootDocumentsHandler(String owner) {
			this.owner = owner;
		}

		public void onFailure(Throwable caught) {
			Window.alert("Seite.getPublicRootFolders getDocuments error: "
					+ caught.getMessage());
		}

		public void onSuccess(List<Document> result) {
			Iterator<Document> i = result.iterator();
			while (i.hasNext()) {
				Document doc = i.next();
				TreeItem newItem = new TreeItem();
				newItem.setHTML(doc.getTitle());
				newItem.setUserObject(doc);
				tree.addItem(newItem);
			}
			publicService.getRootFolders(owner, new RootFolderHandler(owner));
		}
	}

	/**
	 * Der RootFolderHandler f�gt die Ordner der obersten Ebene 
	 * an den Verzeichnisbaum und �ffnet entweder das Dokument 
	 * mit einer bestimmten ID oder das Dokument mit einem bestimmten 
	 * Namen innerhalb eines gegebenen Pfades oder, wenn keine der 
	 * vorigen M�glichkeiten als Parameter in der URL gefunden werden, 
	 * das erste Dokument der obersten Verezichnisebene
	 * 
	 * @author ulli2
	 *
	 */
	private class RootFolderHandler implements AsyncCallback<List<Folder>> {
		private String owner;

		public RootFolderHandler(String owner) {
			this.owner = owner;
		}

		public void onFailure(Throwable caught) {
			Window.alert("Seite.getPublicRootFolders getRootFolders error: "
					+ caught.getMessage());
		}

		public void onSuccess(List<Folder> result) {
			Iterator<Folder> i = result.iterator();
			while (i.hasNext()) {
				Folder folder = i.next();
				TreeItem newItem = new TreeItem();
				newItem.setHTML(folder.getName());
				newItem.setUserObject(folder);
				newItem.addItem("");
				tree.addItem(newItem);
			}
			//String idStr = Netzpult.getDocId();
			String docPath = null; //Window.Location.getParameter(PATH);
			String docName = null; //Window.Location.getParameter(DOCNAME);
			//Window.alert("docPath=" + docPath + " docName=" + docName);
			if(docPath != null && docName != null) {
				publicService.getDocumentForPath(owner, docPath + "/" + docName, new DocumentPathHandler(owner));
			} else if(docId != null) {
				try {
				final int id = Integer.parseInt(docId);
				publicService.getFoldersContaining(owner, id, new FolderListOpener(id));
				} catch(Exception ex) {}
				
			} else {
				TreeItem firstItem = tree.getItem(0);
				if (firstItem != null) {
					Object o = firstItem.getUserObject();
					if (o != null && o instanceof Document) {
						tree.setSelectedItem(firstItem);
					}
				}
			}
			/*if(idStr == null) {
			} else {
			}*/
		}
	}
	
	private class DocumentPathHandler implements AsyncCallback<Document> {

		private String owner;
		public DocumentPathHandler(String owner) {
			this.owner = owner;
		}
		@Override
		public void onFailure(Throwable caught) {
			Window.alert("Seite.DocumentPathHandler error: " + caught.getMessage());
		}

		@Override
		public void onSuccess(Document result) {
			if(result != null) {
				int id = result.getId();
				publicService.getFoldersContaining(owner, id, new FolderListOpener(id));
			} else {
				Window.alert("Document not found");
			}
		}
		
	}

	private class FolderListOpener implements AsyncCallback<List<Folder>> {
		private int id;

		public FolderListOpener(final int id) {
			this.id = id;
		}

		public void onFailure(Throwable caught) {
			Window.alert("Seite.showDocument getFoldersContaining error: "
					+ caught.getMessage());
		}

		@Override
		public void onSuccess(List<Folder> result) {
			if (result != null && result.size() > 0) {
				Folder folder = result.get(0);
				if (folder.getId() == Folder.PUBLIC_FOLDER_ID) {
					tree.openRootDocument(id);
				} else {
					publicService.getPathToFolder(result.get(0), new FolderOpener(folder,
							id));
				}
			} else {
				tree.openRootDocument(id);
			}
		}
	}

	private class FolderOpener implements AsyncCallback<List<Folder>> {
		private Folder folder;
		private int documentId;

		public FolderOpener(final Folder folder, final int documentId) {
			this.folder = folder;
			this.documentId = documentId;
		}

		@Override
		public void onFailure(Throwable caught) {
			Window.alert("Seite.openFolder getPath error: " + caught.getMessage());
		}

		@Override
		public void onSuccess(List<Folder> result) {
			result.add(folder);
			tree.openFolderPath(result, documentId);
		}
	}

	@Override
	public int getGestalt() {
		return Gestalt.ID_SEITE;
	}

}
